# -*- coding: UTF-8 -*-
import mutator.blobmuta
import mutator.stringmuta
import mutator.binarymuta
import random
import bluetooth
import time


class Avdtp:

    # 三种数据包
    # media packet
    VERSION = '' # 2bits
    PADDING = '' # 1bit
    EXTENSION = '' # 1bit
    CSRC_COUNT = '' # 4bits
    MARKER = '' # 1bit
    PAYLOAD_TYPE = '' # 7bits
    SEQUENCE_NUMBER = '' # 16bits
    TIME_STAMP = '' # 32bits
    SSRC = '' # 32bits
    CSRC_LIST = '' # 0-15 items, 32bits each
    # ------------------------------------------------------------------------------------------------------------
    # report packet
    # header
    VERSION_R = '' # 2bits
    PADDING_R = '' # 1bit
    RECEPTION_REPORT_COUNT = '' # 5bits
    PACKET_TYPE = '' # 8bits
    LENGTH = '' # 16bits
    SSRC_R = '' # 32bits
    # sender info
    NTP_TIME_STAMP = '' #64bits
    RTP_TIME_STAMP = '' #32bits
    SENDERS_PACKET_COUNT = '' #32bits
    SENDERS_OCTER_COUNT = '' #32bits
    # report block1
    SSRC_N = '' # 32bits
    FRACTION_LOST = '' # 8bits
    CUMULATIVE_NUMBER_OF_PACKETS_LOST = '' # 24bits
    EXTENDED_HIGHEST_SEQUENCE_NUMBER_RECEIVED = '' # 32bits
    INTER_ARRIVAL_JITTER = '' # 32bits
    LAST_SR_TIMESTAMP = '' # 32bits
    DELAY_SINCE_LAST_SR = '' # 32bits
    # ------------------------------------------------------------------------------------------------------------
    # signal message
    # header
    TRANSACTION_LABEL = '' # bits4-7
    PACKET_TYPE_S = '' # bits3-2 signle=00, start=01, continue=10, end=11
    MESSAGE_TYPE = '' # bits1-0 command=00, general_reject=01, response_accept=10, response_reject=11
    # body
    RFA = '' # 2bits
    SIGNAL_IDENTIFIER = '' # 6bits


    def __init__(self, addr):
        self.addr = addr

    def fuzz_signal_message(self):
        msg = '\x01\x0D'
        rand = random.Random()
        r_flag = random.randint(1, 12)
        msg = self._fs(msg, rand, r_flag)
        network_code = self.send_avdtp(msg)
        return [network_code, r_flag, msg]
        # return [network_code, r_flag, msg]

    def fuzz_report_packet(self):
        header = '\01\x02\x03\x04\x05\x06\x07\x08' # 64bits
        sender_info = '\x81' * 20
        report_block1 = '\x80' * 20
        r_code = random.randint(0, 2)
        rand = random.Random()
        r_flag = random.randint(1, 12)
        if r_code == 0:
            header = self._fs(header, rand, r_flag)
        if r_code == 1:
            sender_info = self._fs(sender_info, rand, r_flag)
        if r_code == 2:
            report_block1 = self._fs(report_block1, rand, r_flag)
        msg = header + sender_info + report_block1
        network_code = self.send_avdtp(msg)
        return [network_code, r_flag, msg]
        # return [network_code, r_code, r_flag, msg, header, sender_info, report_block1]

    def fuzz_media_packet(self):
        vtp = '\x00\x01' # 16bits
        sequence_number = '\x00\x01'
        time_stamp = '\x00\x01\x02\x03'
        ssrc = '\x00\x01\x02\x03'
        csrc_list = '\x00\x01\x02\x03'
        r_code = random.randint(0, 4)
        rand = random.Random()
        r_flag = random.randint(1, 12)
        if r_code == 0:
            vtp = self._fs(vtp, rand, r_flag)
        if r_code == 1:
            sequence_number = self._fs(sequence_number, rand, r_flag)
        if r_code == 2:
            time_stamp = self._fs(time_stamp, rand, r_flag)
        if r_code == 3:
            ssrc = self._fs(ssrc, rand, r_flag)
        if r_code == 4:
            csrc_list = self._fs(csrc_list, rand, r_flag)
        msg = vtp + sequence_number + time_stamp + ssrc + csrc_list
        network_code = self.send_avdtp(msg)
        return [network_code, r_flag, msg]
        # return [network_code, r_code, r_flag, msg, vtp, sequence_number, time_stamp, ssrc, csrc_list]

    def avdtp_random_fuzz(self):
        i = random.randint(0, 2)
        if i == 0:
            return self.fuzz_signal_message()
        if i == 1:
            return self.fuzz_media_packet()
        if i == 2:
            return self.fuzz_report_packet()

    def send_avdtp(self, msg):
        psm = 25 # 0x0019
        sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
        sock.settimeout(5)
        try:
            sock.connect((self.addr, psm))
        except:
            return 1
        try:
            # 同一个包发5次
            for i in range(0, 5):
                sock.send(msg)
        except:
            return 2
        return 0

    def _fs(self, data, rand, flag):

        if (flag == 0):
            return data

        if (flag == 1):
            s = mutator.stringmuta.StringCaseMutator()
            return s.mutationRandomCase(data)

        if (flag == 2):
            s = mutator.stringmuta.UnicodeBomMutator()
            return s.randomMutation(rand)

        if (flag == 3):
            s = mutator.stringmuta.UnicodeBadUtf8Mutator()
            return s.randomMutation(rand)

        if (flag == 4):
            b = mutator.blobmuta.DWORDSliderMutator(data)
            return b.randomMutation(data, rand)

        if (flag == 5):
            b = mutator.blobmuta.BitFlipperMutator(data)
            return b.randomMutation(data, rand)

        b = mutator.blobmuta.BlobMutator(data)
        if (flag == 6):
            return ""  # 返回空字符串

        if (flag == 7):
            return b.changeReduceBuffer(data, rand)

        if (flag == 8):
            return b.changeChangeRangeSpecial(data, rand)

        if (flag == 9):
            return b.changeExpandBuffer(data, rand)

        if (flag == 10):
            return b.changeNullRange(data, rand)

        if (flag == 11):
            return b.changeChangeRange(data, rand)

        if (flag == 12):
            h = mutator.binarymuta.Handler()
            return h.Fuzzit(data)

if __name__ == '__main__':
    addr = 'A4:50:46:A9:5C:DE'
    a = Avdtp(addr)
    for i in range(0, 10):
        time.sleep(0.5)
        print a.fuzz_media_packet()

